﻿using System;
using System.IO;
using System.Runtime.Serialization;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using System.Xml;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Nvigorate.Aspect;
using Nvigorate.Relational.Repository;
using Nvigorate.Relational.State;
using Nvigorate.TestObjects;
using PostSharp;
using PostSharp.Laos;

namespace Nvigorate.Test.Aspect
{
    /// <summary>
    /// Summary description for UnitTest1
    /// </summary>
    [TestClass]
    public class StateTrackingTest
    {
        [TestMethod]
        public void TestInheritedTrackingSerialization()
        {
            var employee = new TestClass()
            {
                FirstName = "Bilbo",
                LastName = "Baggins",
                Age = 27
            };

            (employee as ITrackState).InstanceState.ClearDirtyState();

            employee.FirstName = "Alex";
            employee.LastName = "Robson";

            var serializer = new DataContractSerializer(typeof(TestClass));
            var stream = new MemoryStream();
            serializer.WriteObject(stream, employee);
            stream.Seek(0, SeekOrigin.Begin);
            
            XmlDocument doc = new XmlDocument();
            doc.Load(stream);
            //var message = XmlTextReader.Create(stream).ReadInnerXml();


            stream.Seek(0, SeekOrigin.Begin);
            var newEmployee = serializer.ReadObject(stream) as TestClass;

            var decorator1 = PersistenceDecorator.Create(employee);
            var decorator2 = PersistenceDecorator.Create(newEmployee);
            
            Assert.AreEqual(decorator1.ChangedValues.Count, decorator2.ChangedValues.Count);
            Assert.AreEqual(decorator1.ChangedValues[0].Value1, decorator2.ChangedValues[0].Value1);
            Assert.AreEqual(decorator1.ChangedValues[0].Value2, decorator2.ChangedValues[0].Value2);
            Assert.AreEqual(decorator1.ChangedValues[1].Value1, decorator2.ChangedValues[1].Value1);
            Assert.AreEqual(decorator1.ChangedValues[1].Value2, decorator2.ChangedValues[1].Value2);
            Assert.AreEqual(decorator1.PersistenceTicket, decorator2.PersistenceTicket);
        }

        [TestMethod]
        // This test will fail until PostSharp supports WCF serialization/deserialization
        // of aspect state
        public void TestFailedAspectSerialization()
        {
            var test = new Test2();
            test.Property1 = "test";
            var test3 = test as ITest3;
            test3.Property2 = "test";

            Assert.AreEqual(test3.Property2, "test");

            var serializer = new DataContractSerializer(typeof(Test2));
            var stream = new MemoryStream();
            serializer.WriteObject(stream, test);
            stream.Seek(0, SeekOrigin.Begin);
            var newTest = serializer.ReadObject(stream) as Test2;

            Assert.AreNotEqual("test", (newTest as ITest3).Property2);
        }

        [TestMethod]
        public void TestIIdentitySerializetion()
        {
            var id1 = new InstanceIdentifier();

            var serializer = new DataContractSerializer(typeof(InstanceIdentifier));
            var stream = new MemoryStream();
            serializer.WriteObject(stream, id1);
            stream.Seek(0, SeekOrigin.Begin);
            var id2 = serializer.ReadObject(stream) as InstanceIdentifier;

            Assert.AreEqual(id1.InstanceId, id2.InstanceId);
        }
    }

    [StateTrackingAspect]
    [DataContract]
    [KnownType(typeof(StateTracking))]
    public class TestClass  : StateTracking
    {
        [DataMember]
        public string FirstName { get; set; }

        [DataMember]
        public string LastName { get; set; }

        [DataMember]
        public int Age { get; set; }
    }

    [TestCompositionAspect]
    [DataContract(IsReference = true)]
    public class Test2 //: Test3
    {
        [DataMember]
        public string Property1 { get; set; }
    }

    public interface ITest3
    {
        string Property2 { get; set; }
    }

    [DataContract(IsReference = true)]
    public class Test3 : ITest3
    {
        public string Property2 { get; set; }
    }

    [Serializable]
    [EnableLaosAwareness("PostSharp.Awareness.Serialization", "PostSharp.Awareness.Serialization")]
    public class TestCompositionAspect : CompositionAspect
    {
        public override object CreateImplementationObject(InstanceBoundLaosEventArgs eventArgs)
        {
            return new Test3();
        }

        public override CompositionAspectOptions GetOptions()
        {
            return CompositionAspectOptions.IgnoreIfAlreadyImplemented;
        }

        public override Type GetPublicInterface(Type containerType)
        {
            return typeof(ITest3);
        }
    }
}
